package org.czx.datactruct.second;

import org.czx.datactruct.first.BagInterface;

import java.util.Arrays;
import java.util.Objects;

/**
 * @author czx
 * @date 2020/8/20 13:28
 */
public class ArrayBag<T> implements BagInterface<T> {
    private static final int DEFAULT_CAPACITY = 25;
    private static final int MAX_CAPACITY = 10000;
    private final T[] bag;

    private int numberOfEntries;

    private boolean initialized = false;

    public ArrayBag() {
        this(DEFAULT_CAPACITY);
    }

    @SuppressWarnings("unchecked")
    public ArrayBag(int capacity) {
        if (capacity > MAX_CAPACITY)
            throw new IllegalArgumentException("Attempt to create a bag whose capacity exceeds max_capacity");
        bag = (T[]) new Object[capacity];
        numberOfEntries = 0;
        initialized = true;
    }

    @Override
    public int getCurrentSize() {
        return numberOfEntries;
    }

    @Override
    public boolean isEmpty() {
        return numberOfEntries == 0;
    }

    @Override
    public boolean add(T newEntry) {
        checkInitialization();
        if (isArrayFull()) {
            return false;
        } else {
            bag[numberOfEntries++] = newEntry;
            return true;
        }
    }

    @Override
    public T remove() {
        checkInitialization();
        return removeEntry(numberOfEntries -1);
    }

    @Override
    public T[] toArray() {
        checkInitialization();
        return Arrays.copyOf(bag, numberOfEntries);
    }

    @Override
    public boolean remove(T anEntry) {
        checkInitialization();
        int index = getIndexOf(anEntry);
        return removeEntry(index) != null;
    }

    /**
     * 获取下标
     * @param anEntry
     * @return
     */
    private  int getIndexOf(T anEntry) {
        for (int i = 0; i < numberOfEntries; i++) {
            if (anEntry.equals(bag[i])) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public void clear() {
        while (!isEmpty()) {
            remove();
        }
    }

    @Override
    public int getFrequencyOf(T anEntry) {
        checkInitialization();
        Objects.requireNonNull(anEntry, "anEntry is null");
        int counter = 0;
        for (int i = 0; i < numberOfEntries; i++) {
            if (anEntry.equals(bag[i]))
                counter++;
        }
        return counter;
    }

    @Override
    public boolean contains(T anEntry) {
        checkInitialization();
        return getIndexOf(anEntry) > -1;
    }

    private T removeEntry(int givenIndex) {
        if (!isEmpty() || givenIndex < 0) {
            return null;
        }
        T result = bag[givenIndex];
        bag[givenIndex] = bag[numberOfEntries - 1];
        bag[numberOfEntries - 1] = null;
        numberOfEntries--;
        return result;
    }

    private boolean isArrayFull() {
        return numberOfEntries >= bag.length;
    }

    public void checkInitialization() {
        if(!initialized)
            throw new SecurityException("Array bag is not initialized properly");
    }

}
